You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
12 KiB
308 lines
12 KiB
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Button from "@/components/Componentes/button";
|
|
import { useFlutterBridge } from "@/hooks/useFlutterBridge";
|
|
|
|
export default function TestWebViewPage() {
|
|
const { sendToFlutter, logs, lastEvent, events, isReady } = useFlutterBridge({
|
|
enableLogging: true,
|
|
});
|
|
|
|
const [config, setConfig] = useState<any>(null);
|
|
|
|
useEffect(() => {
|
|
// شناسایی INITIAL_CONFIG
|
|
const initialConfig = events.find((e) => e.type === "INITIAL_CONFIG");
|
|
if (initialConfig) {
|
|
setConfig(initialConfig.payload);
|
|
}
|
|
}, [events]);
|
|
|
|
// تابع تست برای شبیهسازی ایونتهای Flutter
|
|
const simulateFlutterEvent = (type: string, payload: any) => {
|
|
window.dispatchEvent(
|
|
new CustomEvent("flutterEvent", {
|
|
detail: { type, payload, timestamp: Date.now() },
|
|
}),
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 p-4">
|
|
<div className="max-w-4xl mx-auto">
|
|
{/* Header */}
|
|
<div className="bg-white rounded-lg shadow-md p-6 mb-4">
|
|
<h1 className="text-2xl font-bold text-gray-800 mb-2">
|
|
🧪 Flutter WebView Bridge Test
|
|
</h1>
|
|
<div className="flex items-center gap-3">
|
|
<div
|
|
className={`w-3 h-3 rounded-full ${isReady ? "bg-green-500 animate-pulse" : "bg-red-500"}`}
|
|
/>
|
|
<span className="text-sm text-gray-600">
|
|
{isReady ? "✅ Bridge Ready" : "⏳ Waiting for Flutter..."}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* کارت 1: ارسال ایونتها */}
|
|
<div className="bg-white rounded-lg shadow-md p-6">
|
|
<h2 className="text-lg font-bold text-gray-800 mb-4">
|
|
📤 ارسال به Flutter
|
|
</h2>
|
|
<div className="space-y-2">
|
|
<Button
|
|
onClick={() =>
|
|
sendToFlutter("WEB_READY", {
|
|
timestamp: Date.now(),
|
|
url: window.location.href,
|
|
})
|
|
}
|
|
>
|
|
🚀 WEB_READY
|
|
</Button>
|
|
<Button onClick={() => sendToFlutter("REQUEST_LOCATION")}>
|
|
📍 REQUEST_LOCATION
|
|
</Button>
|
|
<Button
|
|
onClick={() =>
|
|
sendToFlutter("REQUEST_CONSULTANT", {
|
|
consultant: "habib@gmail.com",
|
|
})
|
|
}
|
|
>
|
|
👨⚕️ REQUEST_CONSULTANT
|
|
</Button>
|
|
<Button
|
|
onClick={() =>
|
|
sendToFlutter("PAGE_LOADED", {
|
|
page: window.location.pathname,
|
|
})
|
|
}
|
|
>
|
|
📄 PAGE_LOADED
|
|
</Button>
|
|
<Button
|
|
onClick={() =>
|
|
sendToFlutter("ERROR_OCCURRED", {
|
|
message: "Test error",
|
|
code: "TEST_ERROR",
|
|
})
|
|
}
|
|
>
|
|
❌ ERROR_OCCURRED
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* کارت 2: شبیهسازی ایونتهای Flutter */}
|
|
<div className="bg-white rounded-lg shadow-md p-6">
|
|
<h2 className="text-lg font-bold text-gray-800 mb-4">
|
|
📥 شبیهسازی Flutter
|
|
</h2>
|
|
<p className="text-xs text-gray-600 mb-3">
|
|
برای تست بدون Flutter از این دکمهها استفاده کنید
|
|
</p>
|
|
<div className="space-y-2">
|
|
<button
|
|
onClick={() =>
|
|
simulateFlutterEvent("INITIAL_CONFIG", {
|
|
version: "1.0.0",
|
|
layout: {
|
|
breakpoint: "mobile",
|
|
screenWidth: 375,
|
|
screenHeight: 812,
|
|
isMobile: true,
|
|
},
|
|
safeArea: { top: 44, bottom: 34, left: 0, right: 0 },
|
|
platform: { os: "ios", version: "17.2" },
|
|
locale: { languageCode: "fa", isRtl: true },
|
|
})
|
|
}
|
|
className="w-full bg-blue-500 hover:bg-blue-600 text-white text-sm py-2 px-4 rounded-lg transition"
|
|
>
|
|
🔧 INITIAL_CONFIG
|
|
</button>
|
|
<button
|
|
onClick={() =>
|
|
simulateFlutterEvent("KEYBOARD_CHANGED", {
|
|
visible: true,
|
|
height: 336,
|
|
animationDuration: 250,
|
|
})
|
|
}
|
|
className="w-full bg-blue-500 hover:bg-blue-600 text-white text-sm py-2 px-4 rounded-lg transition"
|
|
>
|
|
⌨️ KEYBOARD_CHANGED
|
|
</button>
|
|
<button
|
|
onClick={() =>
|
|
simulateFlutterEvent("ORIENTATION_CHANGED", {
|
|
orientation: "landscape",
|
|
screenWidth: 812,
|
|
screenHeight: 375,
|
|
})
|
|
}
|
|
className="w-full bg-blue-500 hover:bg-blue-600 text-white text-sm py-2 px-4 rounded-lg transition"
|
|
>
|
|
📱 ORIENTATION_CHANGED
|
|
</button>
|
|
<button
|
|
onClick={() =>
|
|
simulateFlutterEvent("SAFE_AREA_CHANGED", {
|
|
top: 0,
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
})
|
|
}
|
|
className="w-full bg-blue-500 hover:bg-blue-600 text-white text-sm py-2 px-4 rounded-lg transition"
|
|
>
|
|
🔒 SAFE_AREA_CHANGED
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* کارت 3: آخرین ایونت */}
|
|
{lastEvent && (
|
|
<div className="bg-green-50 rounded-lg shadow-md p-6 border-2 border-green-200">
|
|
<h2 className="text-lg font-bold text-green-800 mb-4">
|
|
📥 آخرین ایونت دریافتی
|
|
</h2>
|
|
<div className="bg-white p-3 rounded border border-green-300">
|
|
<div className="font-mono text-xs">
|
|
<div className="text-green-600 font-bold mb-2">
|
|
Type: {lastEvent.type}
|
|
</div>
|
|
<div className="text-gray-600">
|
|
<pre className="whitespace-pre-wrap break-all">
|
|
{JSON.stringify(lastEvent.payload, null, 2)}
|
|
</pre>
|
|
</div>
|
|
<div className="text-gray-400 mt-2 text-[10px]">
|
|
{new Date(lastEvent.timestamp || Date.now()).toLocaleString(
|
|
"fa-IR",
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* کارت 4: Config دریافتی */}
|
|
{config && (
|
|
<div className="bg-purple-50 rounded-lg shadow-md p-6 border-2 border-purple-200">
|
|
<h2 className="text-lg font-bold text-purple-800 mb-4">
|
|
⚙️ Initial Config
|
|
</h2>
|
|
<div className="bg-white p-3 rounded border border-purple-300 max-h-[400px] overflow-auto">
|
|
<pre className="font-mono text-xs text-gray-600 whitespace-pre-wrap break-all">
|
|
{JSON.stringify(config, null, 2)}
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* لاگها */}
|
|
<div className="bg-white rounded-lg shadow-md p-6 mt-4">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h2 className="text-lg font-bold text-gray-800">
|
|
📋 لاگها ({logs.length})
|
|
</h2>
|
|
<button
|
|
onClick={() => {
|
|
const logsText = logs.join("\n");
|
|
navigator.clipboard.writeText(logsText);
|
|
alert("لاگها کپی شدند!");
|
|
}}
|
|
className="text-sm text-blue-600 hover:text-blue-800"
|
|
>
|
|
📋 کپی
|
|
</button>
|
|
</div>
|
|
<div className="bg-gray-50 rounded border border-gray-200 p-3 max-h-[400px] overflow-auto">
|
|
{logs.length === 0 ? (
|
|
<p className="text-sm text-gray-500 text-center py-4">
|
|
هنوز لاگی ثبت نشده است
|
|
</p>
|
|
) : (
|
|
<div className="space-y-1">
|
|
{logs.map((log, index) => (
|
|
<div
|
|
key={index}
|
|
className={`font-mono text-xs p-2 rounded ${
|
|
log.includes("[ERROR]")
|
|
? "bg-red-100 text-red-800"
|
|
: log.includes("[SUCCESS]")
|
|
? "bg-green-100 text-green-800"
|
|
: "bg-white text-gray-700"
|
|
}`}
|
|
>
|
|
{log}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* راهنما */}
|
|
<div className="bg-blue-50 rounded-lg shadow-md p-6 mt-4 border-2 border-blue-200">
|
|
<h2 className="text-lg font-bold text-blue-800 mb-4">💡 راهنما</h2>
|
|
<div className="space-y-2 text-sm text-blue-900">
|
|
<p className="font-semibold">🎯 نحوه تست:</p>
|
|
<ol className="list-decimal list-inside space-y-1 mr-2">
|
|
<li>اگر در Flutter هستید، صفحه را load کنید</li>
|
|
<li>
|
|
Flutter باید INITIAL_CONFIG بفرستد (اگر نفرستاد، از دکمه
|
|
شبیهسازی استفاده کنید)
|
|
</li>
|
|
<li>دکمه WEB_READY را بزنید تا به Flutter اطلاع دهید</li>
|
|
<li>سایر دکمهها را تست کنید</li>
|
|
<li>لاگها را در Console و در این صفحه مشاهده کنید</li>
|
|
</ol>
|
|
<p className="font-semibold mt-4">🔧 بدون Flutter:</p>
|
|
<p>
|
|
از دکمههای "شبیهسازی Flutter" استفاده کنید تا ببینید WebView چگونه
|
|
react میکند
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* تمام ایونتها */}
|
|
{events.length > 0 && (
|
|
<div className="bg-white rounded-lg shadow-md p-6 mt-4">
|
|
<h2 className="text-lg font-bold text-gray-800 mb-4">
|
|
📜 تاریخچه ایونتها ({events.length})
|
|
</h2>
|
|
<div className="space-y-2 max-h-[300px] overflow-auto">
|
|
{events.map((event, index) => (
|
|
<div
|
|
key={index}
|
|
className="bg-gray-50 rounded border border-gray-200 p-3"
|
|
>
|
|
<div className="flex items-center justify-between mb-1">
|
|
<span className="font-bold text-sm text-gray-800">
|
|
{event.type}
|
|
</span>
|
|
<span className="text-xs text-gray-500">
|
|
{new Date(
|
|
event.timestamp || Date.now(),
|
|
).toLocaleTimeString("fa-IR")}
|
|
</span>
|
|
</div>
|
|
<pre className="font-mono text-xs text-gray-600 whitespace-pre-wrap break-all">
|
|
{JSON.stringify(event.payload, null, 2)}
|
|
</pre>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|